function varargout = TLManageScalingCtrls(action,varargin)

%TLMANAGESCALINGCTRLS Summary of this function goes here
%
%   TLMANAGESCALINGCTRLS(varagin) Detailed explanation goes here
%
%   Inputs:
%
%
%   Outputs:
%
%
%   Syntax:
%
%
%   Example:
%
%
%   See also:
%
% 
%   Author(s): Xiaobiao Huang
%   Copyright 2013-2020 The Xiaobiao Studio.
%   $Revision: 1.0.0.0 $  $Date: 06-Jul-2013 09:53:21 $

switch action
  
  case 'create'
    pageNum = varargin{1};
    dlgfig = varargin{2};
    dlgdata = varargin{3};
    if length(varargin)> 3
      field = varargin{4};
    else
      field = '';
    end
    if length(varargin) > 4
      currentElement = varargin{5};
    end
    
    [dlgdata] = FcnCreateControls(pageNum, dlgfig, dlgdata);
    varargout = {dlgdata};
  case 'setCtrls'
    % Update controls according to the data stored in their UserData
    % property. The control status is set. This includes the enable status,
    % the value / string as well as background and foreground color where
    % applicable.
    pageNum = varargin{1};
    dlgfig = varargin{2};
    dlgdata = varargin{3};
    FcnSetControls(pageNum, dlgfig, dlgdata);
    varargout = {dlgdata};
  case 'update'
    % The variable controls are updated. In this function, the status of
    % the controls is determined and saved at the controls' UserData
    % property. To actually set the status of the controls, the setCtrl
    % routine has to be called afterwards.
    pageNum = varargin{1};
    dlgdata = varargin{2};
    datafield = varargin{3};
    constraint = varargin{4};
    
    dlgdata = FcnUpdateControls(pageNum, dlgdata, datafield);
    varargout = {dlgdata};
  case 'manage'
    pageNum = varargin{1};
%     dlgfig = varargin{2};
    dlgdata = varargin{3};
    control = varargin{4};
    datafield = varargin{5};
    
    [dlgdata, bModified] = FcnManageControls(pageNum, dlgdata, control, datafield);
        
    varargout{1} = dlgdata;
    varargout{2} = bModified;
    
  otherwise
      % This should never happen.
      error(['Invalid action "' action '"']);
    
end

function dlgdata = FcnCreateControls(pageNum, dlgfig, dlgdata)

ctrlPos  = dlgdata.pageData{pageNum}.ctrlPos;
Children = dlgdata.pageData{pageNum}.children;
pageName = dlgdata.pageNames{pageNum};

defColor = get(0, 'DefaultUIControlBackgroundColor');

% % production code generation options groupbox
% Children.tlcgoptGroupbox = uipanel( ...
%     'Parent',            dlgfig, ...
%     'Title',            {'Production code options'}, ...
%     'Units',            'pixels', ...
%     'Position',          ctrlPos.tlcgoptGroupbox);

% lsb controls
if  isfield(ctrlPos, 'descLabel')
    Children.lsbLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'LSB:', ...
        'Position',          ctrlPos.lsbLabel);
    
    Children.lsbEdit = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'edit', ...
        'Position',          ctrlPos.lsbEdit, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''lsbEdit'')',pageName));
      
    Children.lsbToggleButton = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'pushbutton', ...
        'Position',          ctrlPos.lsbToggleButton, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''lsbToggleButton'')',pageName));
end

% offset controls
if  isfield(ctrlPos, 'offsetLabel')
    Children.offsetLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'Offset:', ...
        'Position',          ctrlPos.offsetLabel);
    
    Children.offsetEdit = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'edit', ...
        'Position',          ctrlPos.offsetEdit, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''offsetEdit'')',pageName));    
end

% max controls
if  isfield(ctrlPos, 'upperLimitLabel')
    Children.upperLimitLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'Max:', ...
        'Position',          ctrlPos.upperLimitLabel);
    
    Children.upperLimitEdit = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'edit', ...
        'Position',          ctrlPos.upperLimitEdit, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''upperLimitEdit'')',pageName));
end

% upperLimitCheckbox controls
if isfield(ctrlPos,'upperLimitCheckbox')
		Children.upperLimitCheckbox = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'checkbox', ...
        'String',            'Saturate', ...
        'Position',          ctrlPos.upperLimitCheckbox, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''upperLimitCheckbox'')',pageName));
end

% min controls
if  isfield(ctrlPos, 'lowerLimitLabel')
    Children.lowerLimitLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'Min:', ...
        'Position',          ctrlPos.lowerLimitLabel);
    
    Children.lowerLimitEdit = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'edit', ...
        'Position',          ctrlPos.lowerLimitEdit, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''lowerLimitEdit'')',pageName));
end

% lowerLimitCheckbox controls
if isfield(ctrlPos,'upperLimitCheckbox')
		Children.lowerLimitCheckbox = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'checkbox', ...
        'String',            'Saturate', ...
        'Position',          ctrlPos.lowerLimitCheckbox, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''lowerLimitCheckbox'')',pageName));
end

% implemented controls
if  isfield(ctrlPos, 'implementedLabel')
    Children.implementedLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'Implemented', ...
        'Position',          ctrlPos.implementedLabel);
    
    Children.upperImplementedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.upperImplementedValue);
    
     Children.lowerImplementedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.lowerImplementedValue);
end

% calcuated controls
if  isfield(ctrlPos, 'calculatedLabel')
    Children.calculatedLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'Calcuated', ...
        'Position',          ctrlPos.calculatedLabel);
    
    Children.upperCalculatedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.upperCalculatedValue);
    
     Children.lowerCalculatedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.lowerCalculatedValue);
end

% simulated controls
if  isfield(ctrlPos, 'simulatedLabel')
    Children.simulatedLabel = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            'of element', ...
        'Position',          ctrlPos.simulatedLabel);
    
    Children.upperSimulatedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.upperSimulatedValue);
    
     Children.lowerSimulatedValue = uicontrol( ...
        'Parent',            Children.tlcgoptGroupbox, ...
        'Style',             'text', ...
        'String',            ' ', ...
        'Position',          ctrlPos.lowerSimulatedValue);
end

dlgdata.pageData{pageNum}.children = Children;

%-----------------------------------------------------------------------------------------
% FcnManageControls manages the variable control callbacks
%
% INPUT ARGUMENTS
%   pageNum      number of tab
%   dlgdata      dialog data
%   control      control which has been used
%   datafield    variable for which the controls are created, e.g. 'output'
%
% OUTPUT ARGUMENTS
%   dlgdata      dialog data. Includes children field with control data
%   bModified    flag which indicates whether an update of the controls is
%                needed
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageControls(pageNum, dlgdata, control, datafield)

Children = dlgdata.pageData{pageNum}.children;

if dlgdata.bIsSFOrEMLObject
    currentdata = dlgdata.data;
    currentextdata = dlgdata.extdata;
else
    % currentSignal is used by blocks with user-specified variables (e.g.
    % custom code block, bus port blocks)
    if isfield(dlgdata, 'currentSignal')
        signalNum = dlgdata.currentSignal;
    else
        dlgdata.currentSignal = 1;
        signalNum = 1;
    end
    
    if isfield(dlgdata, 'currentNode') && ~isempty(dlgdata.currentNode)
        signalNum = dlgdata.currentNode;
    end
    
    currentdata = dlgdata.data.(datafield)(signalNum);
    currentextdata = dlgdata.extdata.(datafield)(signalNum);
end
data = dlgdata.data;
bModified = 0;

if ~isfield(currentextdata, 'currentElement')
    currentextdata.currentElement = 1;
end
currentElement = currentextdata.currentElement;

switch control        
    case 'lsbToggleButton'
        lsbToggleButtonString = get(Children.lsbToggleButton,'String');
				currentdata.arb = 1;
				if strcmp(lsbToggleButtonString,'arb')
					currentdata.arb = 0;
					set(Children.lsbToggleButton,'String','2^');
				end
        %bPerformSync = 1;
        bModified = 1;
		case 'lsbEdit'
				lsb = str2num(get(Children.lsbEdit,'String'));
				lsbToggleButtonString = get(Children.lsbToggleButton,'String');
				if strcmp(lsbToggleButtonString,'2^')
					lsb = power(2,lsb);
				end
				currentdata.lsb = lsb;
				bModified = 1;
		case 'offsetEdit'
				offset = str2num(get(Children.offsetEdit,'String'));
				if isempty(offset)
					offset = currentdata.offset;
				end
				currentdata.offset = offset;
				bModified = 1;
		case 'upperLimitEdit'
				max = str2num(get(Children.upperLimitEdit,'String'));
				if isempty(max)
					max = nan;
				end
				currentdata.max(currentElement) = max;	
				bModified = 1;
		case 'upperLimitCheckbox'
				checkmax = get(Children.upperLimitCheckbox,'Value');
				currentdata.checkmax(currentElement) = checkmax;	
				bModified = 1;
		case 'lowerLimitEdit'
				min = str2num(get(Children.lowerLimitEdit,'String'));
				if isempty(min)
					min = nan;
				end
				currentdata.min(currentElement) = min;
				bModified = 1;
		case 'lowerLimitCheckbox'
				checkmin = get(Children.lowerLimitCheckbox,'Value');
				currentdata.checkmin(currentElement) = checkmin;	
				bModified = 1;
end

if bModified
    if dlgdata.bIsSFOrEMLObject
        data = currentdata;
        dlgdata.extdata = currentextdata;
    else
        data.(datafield)(signalNum) = currentdata;
        dlgdata.extdata.(datafield)(signalNum) = currentextdata;
    end
    dlgdata.data = data;
end


%-------------------------------------------------------------------------------
% FcnUpdateControls determines the status of the variable controls
%
% INPUT ARGUMENTS
%   pageNum      number of tab
%   dlgdata      dialog data
%   datafield    variable for which the controls are created, e.g. 'output'
%
% OUTPUT ARGUMENTS
%   dlgdata      Dialog data. Includes children field with control data.
%-------------------------------------------------------------------------------
function dlgdata = FcnUpdateControls(pageNum, dlgdata, datafield)

Children = dlgdata.pageData{pageNum}.children;
fielddata = dlgdata.data.(datafield);
% default control status

% default value
lsbToogleButtonString = '2^';
% max 
max = fielddata.max(1);
if isnan(max)
	max = '';
end

% min 
min = fielddata.min(1);
if isnan(min)
	min = '';
end

if strcmp(fielddata.type,'Bool')
  max = 1;
  min = 0;
end

% offset 
offset = fielddata.offset(1);

% lsb
lsb = fielddata.lsb(1);
lsbvalue = log2(fielddata.lsb(1));
if fielddata.arb
  lsbToogleButtonString = 'arb';
  lsbvalue = fielddata.lsb(1);
end

% simulatedLabel


% calculate the implemented value
% Range*LSB + 0ffset
range = struct('Bool',				[0  1], ... % type  length  isunsigned
							 'Int8',				[8  0], ...
							 'UInt8',				[8  1], ...
							 'Bool8',				[8  1], ...
							 'Int16',				[16 0], ...
							 'ADC',					[16 0], ...
							 'UInt16',			[16 1], ...
							 'DAC',					[16 1], ...
							 'Int32',				[32 0], ...
							 'UInt32',			[32 1], ...
							 'Float32',			[32 0], ...
							 'CONTINUOUS',  [32 0], ...
							 'Float64',			[64 0], ...
							 'Bitfield',		[8	1]);
						 
pow = range.(fielddata.type)(1);
isunsigned = range.(fielddata.type)(2);

rangeLow = -(power(2,pow-1))+1;
rangeHigh = power(2,pow-1);
if isunsigned
	rangeLow = 0;
	rangeHigh = power(2,pow)-1;
end

implementedHighValue = rangeHigh * lsb + offset;
implementedLowValue = rangeLow * lsb + offset;

if max <= implementedHighValue & max >= implementedLowValue
	implementedHighValue = max;
end

if min <= implementedHighValue & min >= implementedLowValue
	implementedLowValue = min;
end

% check the value range
rangeError = 0;
if isfield(fielddata,'value') & ...
		(str2num(fielddata.value) > implementedHighValue | str2num(fielddata.value) < implementedLowValue)
	rangeError = 1;
end


editstatus = 2; % 0 off 1 inactive 2 on
if ~isempty(fielddata.scaling)
	editstatus = 1;
end

upperLimitEditCtrlStatus        = struct('enable', 1, 'string', num2str(max));
lowerLimitEditCtrlStatus        = struct('enable', 1, 'string', num2str(min));
if any(strfind(fielddata.class,'CAL')) | ~strcmp(dlgdata.maskType,'TL_Constant')
  upperLimitEditCtrlStatus        = struct('enable', 2, 'string', num2str(max));
	lowerLimitEditCtrlStatus        = struct('enable', 2, 'string', num2str(min));
end

lsbEditCtrlStatus               = struct('enable', editstatus, 'string', num2str(lsbvalue),'iserror',rangeError); % 0 off 1 inactive 2 on
lsbToggleButtonCtrlStatus       = struct('enable', editstatus, 'string', lsbToogleButtonString);
offsetEditCtrlStatus            = struct('enable', editstatus, 'string', num2str(offset),'iserror',rangeError);

simulatedLabelCtrlStatus        = struct('enable', 1);
upperSimulatedValueCtrlStatus   = struct('enable', 2, 'string', '');
lowerSimulatedValueCtrlStatus   = struct('enable', 2, 'string', '');

implementedLabelCtrlStatus      = struct('enable', 1);
upperImplementedValueCtrlStatus = struct('enable', 2, 'string', num2str(implementedHighValue),'iserror',rangeError);
lowerImplementedValueCtrlStatus = struct('enable', 2, 'string', num2str(implementedLowValue),'iserror',rangeError);

calculatedLabelCtrlStatus       = struct('enable', 1);
upperCalculatedValueCtrlStatus  = struct('enable', 2);
lowerCalculatedValueCtrlStatus  = struct('enable', 2);

FcnSaveCtrlUserData(Children, 'lsbEdit',lsbEditCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'lsbToggleButton',lsbToggleButtonCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'offsetEdit',offsetEditCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'upperLimitEdit',upperLimitEditCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'lowerLimitEdit',lowerLimitEditCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'simulatedLabel',simulatedLabelCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'upperSimulatedValue',upperSimulatedValueCtrlStatus, 0);
FcnSaveCtrlUserData(Children, 'lowerSimulatedValue',lowerSimulatedValueCtrlStatus, 0);
FcnSaveCtrlUserData(Children, 'implementedLabel',implementedLabelCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'upperImplementedValue',upperImplementedValueCtrlStatus, 0);
FcnSaveCtrlUserData(Children, 'lowerImplementedValue',lowerImplementedValueCtrlStatus, 0);
FcnSaveCtrlUserData(Children, 'calculatedLabel',calculatedLabelCtrlStatus, 1);
FcnSaveCtrlUserData(Children, 'upperCalculatedValue',upperCalculatedValueCtrlStatus, 0);
FcnSaveCtrlUserData(Children, 'lowerCalculatedValue',lowerCalculatedValueCtrlStatus, 0);

if isfield(Children,'lowerLimitCheckbox')
	lowerLimitCheckboxCtrlStatus = struct('enable', 2, 'value',fielddata.checkmin);
	FcnSaveCtrlUserData(Children, 'lowerLimitCheckbox',lowerLimitCheckboxCtrlStatus, 1);
end

if isfield(Children,'upperLimitCheckbox')
	upperLimitCheckboxCtrlStatus = struct('enable', 2, 'value',fielddata.checkmax);
	FcnSaveCtrlUserData(Children, 'upperLimitCheckbox',upperLimitCheckboxCtrlStatus, 1);
end

%-----------------------------------------------------------------------------------------
% FcnSaveCtrlUserData saves UserData at controls
%
% INPUT ARGUMENTS
%   Children     Structure with controls
%   ctrl         Control for which the status is set
%   ctrlStatus   Status of this control
%   bInactive    0 if "inactive" status should be "off" instead
%-----------------------------------------------------------------------------------------
function FcnSaveCtrlUserData(Children, ctrl, ctrlStatus, bInactive)

% change state to string
if isfield(ctrlStatus, 'enable')
    enableState = ctrlStatus.enable;
    switch enableState
        case 0
            % off
            ctrlStatus.enable  = 'off';
        case 1
            % inactive
            if bInactive
                ctrlStatus.enable  = 'inactive';
            else
                ctrlStatus.enable  = 'off';
            end
        case 2
            % on
            ctrlStatus.enable  = 'on';
        otherwise
            error('Internal Error. Please contact TorstenPi!');
    end
end

% set status to control
if isfield(Children, ctrl)
    ctrl = Children.(ctrl);
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = ctrlStatus;
    set(ctrl, 'UserData', UserData);
end

%-----------------------------------------------------------------------------------------
% FcnSetControls sets status of the controls
%
% INPUT ARGUMENTS
%   pageNum    number of the tab
%   dlgfig     figure handle of dialog
%   dlgdata    dialog data
%-----------------------------------------------------------------------------------------
function [dlgdata] = FcnSetControls(pageNum,dlgfig,dlgdata)

% list of controls for which the status is set
ctrlsList = {...
    'lsbEdit'...
    'lsbToggleButton' ...
    'offsetEdit'...
    'upperLimitEdit' ...
    'lowerLimitEdit'...
    'upperImplementedValue' ...
    'lowerImplementedValue'...
    'upperCalculatedValue' ...
    'lowerCalculatedValue'...
    'upperSimulatedValue'...
    'lowerSimulatedValue'...
    };

Children = dlgdata.pageData{pageNum}.children;

if isfield(Children,'upperLimitCheckbox')
	ctrlsList = [ctrlsList 'upperLimitCheckbox'];
end

if isfield(Children,'lowerLimitCheckbox')
	ctrlsList = [ctrlsList 'lowerLimitCheckbox'];
end

% dlgfig = get(dlgfig,'Parent');
% Set status of controls
TLSetCtrlsStatus(dlgfig, Children, ctrlsList);

% set string in status line
controlUserData = get(dlgdata.SystemButtons.StatusLabel,'UserData');
if isfield(controlUserData, 'ctrlStatus') && ~isempty(controlUserData.ctrlStatus.string)
    set(dlgdata.SystemButtons.StatusLabel,...
        'string',  controlUserData.ctrlStatus.string);
else
    % set default status string
    set(dlgdata.SystemButtons.StatusLabel,...
        'string',  controlUserData.defaultString);
end
